﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ScriptCompare
{
    public class UnorderedLineCollection : LineCollectionBase, ILineCollection
    {
        public UnorderedLineCollection(IEnumerable<ScriptLine> source) : base(source) { }

        #region ILineCollection Members

        public ILineCollection CreateBlank()
        {
            // Get the number of lines in this collection
            int lines = this._lines.Count;

            // Create a list to hold the blank lines
            ScriptLine[] blanks = new ScriptLine[lines];

            // Create a new blank line and add it to the proper location
            for (int itr = 0; itr < lines; itr++)
            {
                blanks[itr] = new ScriptLine("", itr);
            }

            // Return the new Line Collection
            return new UnorderedLineCollection(blanks);
        }

        bool MergeCompare(ILineCollection compareTo)
        {
            // Keep track of similarity
            bool isSame = true;

            // Make sure the comparison target is an ordered line collection 
            if (!(compareTo is OrderedLineCollection))
            {
                throw new InvalidOperationException("An OrderedLineCollection can only be compared to another OrderedLineCollection.");
            }

            // Setup some aliases
            IList<ScriptLine> allLinesLeft = new List<ScriptLine>(this.Lines);
            IList<ScriptLine> allLinesRight = new List<ScriptLine>(compareTo.Lines);

            // Number of lines
            int cntLinesLeft = allLinesLeft.Count;
            int cntLinesRight = allLinesRight.Count;

            // Iterator variables
            ScriptLine? lineLeft = null;
            ScriptLine? lineRight = null;
            int index = 0;

            /* NOTE: Consider the right side to be the source.
             * Go through both collections and add items, in the order of the source, to the resultant
             * collections. If the source doesn't contain a particular line from the target, we add a
             * space. */
            for (int i = 0; (i < cntLinesLeft && i < cntLinesRight); i++)
            {
                // Read in the left and right lines
                if (i < cntLinesLeft) { lineLeft = allLinesLeft[i]; } else { lineLeft = null; }
                if (i < cntLinesRight) { lineLeft = allLinesRight[i]; } else { lineRight = null; }
                
                // First, check to see if the right line is null or the left line is null
                if (lineLeft == null && lineRight != null)
                {   
                    // First, check to see the right line is empty
                    if (lineRight.Value.IsEmpty)
                    {
                        // Skip it
                        continue;
                    }
                    // Next, see if the line exists anywhere in the collection
                    else if ((index = allLinesLeft.IndexOf(lineRight.Value)) >= 0)
                    {
                        // Swap the lines in the left collection
                        allLinesLeft.Swap(i, index);
                    }
                    else
                    {
                        isSame = false;
                        cntLinesLeft++;

                        // Add a blank to the left
                        allLinesLeft.Insert(i, new ScriptLine("", i));

                        // Toggle the right line
                        allLinesRight[i].HighlightLine();
                    }
                }
                // Next check to see if the right is null
                else if (lineRight == null && lineLeft != null)
                {
                    // First, check to see the left line is empty
                    if (lineLeft.Value.IsEmpty)
                    {
                        // Skip it
                        continue;
                    }
                    // See if the line exists anywhere in the collection
                    else if ((index = allLinesRight.IndexOf(lineLeft.Value)) >= 0)
                    {
                        // Swap the lines in the left collection
                        allLinesRight.Swap(i, index);
                    }
                    else
                    {
                        isSame = false;
                        cntLinesRight++;

                        // Add a blank to the left
                        allLinesRight.Insert(i, new ScriptLine("", i));

                        // Toggle the left line
                        allLinesLeft[i].HighlightLine();
                    }
                }
                // At this point, both lines are not null
                else
                {
                    // Check to see if they are the same
                    if (
                        (lineLeft.Value.IsEmpty && lineRight.Value.IsEmpty) ||
                        (lineLeft.Value.IsComment && lineRight.Value.IsComment) ||
                        (lineLeft.Value.Matches(lineRight.Value))
                       )
                    {
                        // continue
                        continue;
                    }
                    else
                    {
                        // Otherwise, they do not match. Again, using the right as the source, see if it exists anywhere in the left                    
                        if ((index = allLinesLeft.IndexOf(lineRight.Value)) >= 0)
                        {
                            // Swap the lines in the left collection
                            allLinesLeft.Swap(i, index);
                        }
                        else
                        {
                            isSame = false;
                            cntLinesLeft++;

                            // Add a blank to the left
                            allLinesLeft.Insert(i, new ScriptLine("", i));

                            // Toggle the right line
                            allLinesRight[i].HighlightLine();
                        }
                    }
                }
            }   // End line checking

            // Update the line collections of right and left
            this.ReplaceLines(allLinesLeft);
            compareTo.ReplaceLines(allLinesRight);

            // Return similarities
            return (isSame);
        }

        #endregion
    }
}
